import {Ref, ref, reactive} from 'vue'
import {MsgUtil, ObjUtil} from '@/utils'
import {CloseModelEvent} from '@/types'


interface ConstructorParams {
    rowKey: string
    tplRecord: Record<string, any>
    rawRecord?: Record<string, any>
    emit: any

}

export class EditModal {

    /**
     * 单条数据的Key字段名称
     * */
    rowKeyName = 'id'

    /**
     * 绑定到表单的Ref对象
     * */
    formRef = ref(null);


    /**
     * 表单绑定对象
     * */
    formState: Ref<Record<string, any>>

    /**
     * 原始独享
     * */
    protected rawRecord: Record<string, any>

    /**
     *  执行提交按钮之前的拦截方法
     * */
    beforeSubmit: any

    /**
     *  数据验证通过之后执行的方式
     * */
    afterValidateHandler: any

    /**
     * 是否是数据修改模式
     * */
    isUpdate = false

    addRequest: any

    updateRequest: any

    /**
     * Vue提交对象
     * */
    emit: any


    LAYER = reactive({
        title: '',
        visible: true,
        width: 640,
        alignCenter: false,
        top: 50,
        closable: true,
        escToClose: true,
        unmountOnClose: true,
        maskClosable: false,
        okButtonProps: {disabled: false, loading: false},
        cancelButtonProps: {disabled: false},
        okText: '确定保存'
    })

    /*
    * 锁定窗口事件
    * */
    lockMd = () => {
        this.LAYER.okButtonProps.loading = true;
        this.LAYER.cancelButtonProps.disabled = true;
        this.LAYER.closable = false;
        this.LAYER.escToClose = false;
    }

    /*
  * 解锁窗口操作
  * */
    unLockMd = () => {
        this.LAYER.okButtonProps.loading = false
        this.LAYER.cancelButtonProps.disabled = false;
        this.LAYER.closable = true;
        this.LAYER.escToClose = true;
    }

    /**
     * @desc 初始化窗口对象
     * @param rowKey 数据组件Key 一般情况都为 id
     * @param tplRecord 后端提供的DTO 对象模板
     * @param rawRecord 需要修改的原始数据
     * @param emit 定义的回调方法入口
     * */
    constructor({tplRecord, rawRecord, rowKey, emit}: ConstructorParams) {
        this.rowKeyName = rowKey
        this.emit = emit
        this.isUpdate = rawRecord?.[rowKey] !== undefined
        if (this.isUpdate) {
            this.rawRecord = rawRecord
            this.formState = ref(ObjUtil.pick(tplRecord, rawRecord))
        } else {
            // 深拷贝一次对象
            const data = JSON.parse(JSON.stringify(tplRecord))
            this.formState = ref(data)
        }
    }

    /**
     * @desc 修改窗口宽度
     * @param title 窗口标题
     * @param width 窗口宽度数值
     * */
    setMD(title, width = 640) {
        if (width <= 200) {
            MsgUtil.message("窗口大小不能小于200像素")
            return
        }
        this.LAYER.width = width;
        this.LAYER.title = title;
        return this;
    }


    /**
     * @desc 配置数据新增的执行方法
     * @param request 执行数据新增的执行方法
     * */
    setAddRequest(request) {
        this.addRequest = request
        return this
    }

    /**
     * @desc 配置数据修改的执行方法
     * @param request 执行数据修改的执行方法
     * */
    setUpdateRequest(request) {
        this.updateRequest = request
        return this
    }

    /**
     * 执行数据新增操作
     * */
    private addAction = async () => {
        if (typeof this.addRequest !== 'function') throw new Error('尚未初始化数据新增的执行方法,setAddXhr 方法进行初始化')
        const {message} = await this.addRequest(this.formState.value)
        MsgUtil.notify('操作成功!', message)
        this.onCancel('RELOAD')
    }

    /**
     * 执行数据修改操作
     * */
    private updateAction = async () => {
        if (typeof this.updateRequest !== 'function') throw new Error('尚未初始化数据修改的执行方法,updateXhr 方法进行初始化')
        const key = this.rawRecord[this.rowKeyName]
        const {message} = await this.updateRequest(key, this.formState.value)
        MsgUtil.notify('操作成功!', message)
        this.onCancel('REFRESH')
    }

    /**
     * 窗口提交事件
     * */
    onSubmit = async () => {
        if (typeof this.beforeSubmit === 'function') this.beforeSubmit()
        const err = await this.formRef.value.validate();
        if (err !== undefined) return false


        let run = true
        if (typeof this.afterValidateHandler === 'function') run = this.afterValidateHandler()
        if (!run) return false;


        try {
            this.lockMd()
            this.isUpdate ? await this.updateAction() : await this.addAction()
            return true;
        } catch (err) {
            console.error(err)
            return false
        } finally {
            this.unLockMd();
        }


    }


    /**
     * 窗口事件
     * */
    onCancel = (eventCode: CloseModelEvent = 'NONE') => {
        this.formState.value = {}

        this.emit('cancel', eventCode)
    }
}
